Binding classes

This chapter introduces the classes that Python scripts can use in Birdee. We use Python type hint syntax to show the members of the classes.

Error classes

class CompileError:
    linenumber: int #readonly, the line number of the error
    pos: int #readonly, the position of characters in the line
    msg: str #readwrite, the error message

The compile error that was actually raised. It can be got from function get_compile_error.

class TokenizerError:
    linenumber: int #readonly, the line number of the error
    pos: int #readonly, the position of characters in the line
    msg: str #readwrite, the error message

The compile error that was actually raised. It can be got from function get_tokenizer_error.

Containers and Ownership pointers

Ownership pointer

class SOMEUniquePtr:
    def get() -> SOME

The ownership pointer of the AST class SOME. SOME above can be replaced by some AST node classes, which can be StatementAST, etc. This UniquePtr class represents the ownership of an AST node. If the ownership is not transfered to another AST node, the AST node will be destroyed when Python runtime reclaim the memory of this ownership pointer object. A reference to AST node is a pointer that has no ownership of the node. You can use get() on a ownership pointer to get the reference of the AST node. You cannot get fields or call member functions directly on ownership pointers. Instead, you can operate on a reference by calling get(). For more information, please refer to the "Compile time scripts" chapter of Birdee language manual.

For most of the sub-classes of StatementAST and ExprAST, if you get a field of them with type StatementAST, you will get a reference. If you assign a value to the StatementAST typed fields, you usually need a StatementASTUniquePtr and the field will take over the ownership.

List

class SOMEList:
    def pop_back(): ... # remove the last item
    def push_back(itm: SOMEUniquePtr): ... # append an item to the list, will take the owner ship of the itm
    def __getitem__(idx: int): ...
    def __setitem__(idx: int, itm: SOMEUniquePtr): ... #will take the ownership of the itm
    def __len__() -> int: ...
    def __iter__(): ...

A list of AST nodes. SOME above can be replaced by some AST node classes, which can be MemberFunctionDef, FieldDef, etc. You can use the list as a normal Python list. The [...] and for ... in ... are allowed on AST node lists.

AST classes

BasicType

class BasicType(Enum):
    CLASS
    NULL
    FUNC
    VOID
    BYTE
    SHORT
    INT
    LONG
    ULONG
    UINT
    FLOAT
    DOUBLE
    BOOLEAN
    POINTER
    PACKAGE

It is an enum which represents the basic types.

ResolvedType

class ResolvedType:
    base: BasicType # readonly, the base type of the resolved type
    index_level: int # readwrite, is it an array? 0 for not array, 1 for 1D array and so on
    def is_class() -> bool: ... # if it is a class (not struct)
    def is_integer() -> bool: ... # if it is an integer
    def get_detail() -> ???: ... # get the detailed info of the type. See comments below.
    def set_detail(_base: BasicType, detail): ... # set the basic type and details
    def __init__():...
    def __str__() -> str: ... # convert the type into a string
    def __eq__(other: ResolvedType) -> bool: ... # if another type is equal to this

The internal class that represents a resolved type. It basically contains three parts. * base is the base type of the type. If it is a basic type (e.g. int), this field should be a enum value (e.g. BasicType.INT). If the type is a class/struct, this field should be BasicType.CLASS. The detailed ClassAST of the referenced class can be found by detail. If the base type is a BasicType.FUNC, the type is a functype or closure. * index_level is the dimension of the array. If it is 0, the type is not an array. If it is larger than 0, the type is a index_level-D array of type specified by base. * detail is the detailed information of the type. If the type is a class/struct type, get_detail() will return a reference to ClassAST of the referenced class. If the type is a functype or closure, get_detail() will return a reference to PrototypeAST.

SourcePos

class SourcePos:
    source_idx: int #readwrite, a unique index for the source file name
    line: int #readwrite, the line number
    pos: int #readwrite, the position of characters in the line

This class represents a position in the source code. Most of the AST nodes contains a SourcePos object to mark the position of the AST in the source file.

PrototypeAST

class PrototypeAST:
    prefix: str # readonly. returns the symbol prefix of the Function definition. 
    # For example, if the function is defined in a module "com.a", the prefix should be "com.a." 
    name: str # readwrite. the function name or function type name
    return_type: ResolvedType # readwrite. The return type of the function
    args: VariableSingleDefASTList # readonly. The argument definitions
    is_closure: bool # readwrite. if the function is a closure
    cls: ClassAST # readwrite. The class where the function is defined. Can be None if is not a member function

This class holds the information of a function type (functype or closure). It also holds information of a function definition.

Template Parameters and Arguments

Birdee's function and class templates can have placeholders for types and constant values. The placeholders which are declared in the template definition is called "template parameters" in Birdee compiler. For example, the class

class Templ[T1,T2, v as int]

end

has three template parameters, namely T1, T2 and v. The first two are type paramters and the last is constant value parameter. In Python binding, you can access the parameters via the TemplateParameter, TemplateParameters_ClassAST and TemplateParameters_FunctionAST.

The class TemplateParameter represents one single template parameter. TemplateParameters_ClassAST and TemplateParameters_FunctionAST are the template parameter lists for classes and functions

class TemplateParameter:
    type: BasicType # readonly. It is CLASS if the template parameter is a type parameter
    # Otherwise, it is a constant value parameter with the type
    name: str # readwrite. The name of the parameter 

class TemplateParameters_ClassAST: #TemplateParameters_FunctionAST is the same
    params: TemplateParameterList # readonly
    source: str # readonly. The source code of the template

On the other hand, the template arguments are the acutal types/values that are given to the templates when using an instance of template.

class TemplateArgument:
    class TemplateArgumentType(Enum):
        TEMPLATE_ARG_TYPE
        TEMPLATE_ARG_EXPR

    kind: TemplateArgumentType # readwrite, the kind of the argument, type? value?
    resolved_type: ResolvedType # readwrite. The resolved type for the type argument or the value
    expr: StatementAST # readwrite. The value expression of the argument. Writing to it needs an ownership pointer and will take the ownership of it

AST base classes

class StatementAST:
    pos: SourcePos # readwrite
    def run(func): ... # run a function "func" on the sub AST nodes of this node
    def copy(func) -> StatementASTUniquePtr: ... # copy this AST node

class ExprAST(StatementAST):
    resolved_type: ResolvedType #readwrite, the type of the expression
    def is_lvalue() -> bool: ... # returns true if the expression is an LValue (has an address)

These two classes are super classes for most of the AST nodes.

FunctionAST

This class represents a function definition (with body), or a function declaration (without body).

class FunctionAST(ExprAST):
    body: StatementASTList # readonly, the list of statement AST of the body of the function
    proto: PrototypeAST # readonly, the prototype of the function
    capture_on_stack: bool # readwrite, if the captured variables of the function is stored on stack
    is_declare: bool # readwrite, if the function is a declaration or imported from other module
    is_template_instance: bool # readwrite, if the function is an instance of template function
    is_imported: bool # readwrite, if the function is imported from other modules
    template_instance_args: TemplateArgumentList # readonly, if is an template instance, the template argument list; Otherwise None
    template_source_func: FunctionAST # readonly, if is an template instance, the source template function; Otherwise None
    capture_this: bool # readwrite, if the function captures "this"
    is_template: bool # readonly, if the function is a template function
    parent: FunctionAST # readonly, if is an closure function, the function that contains the current function; Otherwise None
    link_name: str # readwrite, the link-time name for the function. 
    # Specifiled by the "alias" clause of function definition
    template_param: TemplateParameters_FunctionAST # readonly, if is a template function, the template parameters; Otherwise, None

AnnotationStatementAST

An annotated statement is wrapped in an AnnotationStatementAST. For example, Birdee code

@some
function f()
end

has an AnnotationStatementAST which contains a FunctionAST.

class AnnotationStatementAST(StatementAST):
    @static
    def new(annotations: list, impl: StatementASTUniquePtr): ... 
    #static function, create a new AnnotationStatementAST node. "annotations" is a list of string that are for annotations
    #"impl" is the annotated AST node. Will take the ownership of "impl"
    is_expr: bool # readwrite, if this annotated statement is an expression
    anno: list # readwrite, a list of annotations in string
    impl: StatementASTUniquePtr # the ownership pointer of the annotated AST. Reading this field will yield a reference

ScriptAST

The AST for the embeded scripts, i.e., between {@ @}.

class ScriptAST(ExprAST):
    @static
    def new(script: str, is_top_level:bool):... # creates a new ScriptAST. "is_top_level" specifies whether is script is in the top level.
    stmt: StatementASTList # readonly, the generated statement AST by the script
    script: str # readwrite, the script

ResolvedIdentifierExprAST

class ResolvedIdentifierExprAST(ExprAST):
    def is_mutable()-> bool : ... # is this value mutable?

This class is an abstract class, which represents an simple primary expression (function name or variable), or a number literal, etc.

StringLiteralAST

class StringLiteralAST(ResolvedIdentifierExprAST):
    @static
    def new(value: str): ... # create a new StringLiteralAST 
    value: str  # the string value of the literal

This class of AST represents string literals, usually surrounded by a pair of ", like "Hello" in Birdee code.

NumberExprAST

The AST for number literals. e.g. 1.23.

class NumberExprAST(ResolvedIdentifierExprAST):
    @static
    def new(type: BasicType, value): ... # creates a new number with given type
    value: ??? # readwrite, the value of the number literal
    type: BasicType # readwrite, the type of the number literal
    def __str__()->str : ... # convert the value to a Python string

ArrayInitializerExprAST

class ArrayInitializerExprAST(ExprAST):
    @static
    def new(impl: list): ... # create an array from a list of StatementASTUniquePtr 
    values: ExprASTList # readonly, the list of expressions in the array

This class of AST represents array literals, like [1,2,3,4].

ReturnAST

class ReturnAST(StatementAST):
    @static
    def new(retv: StatementASTUniquePtr): ... # create a return statement from an expression. Takes the ownership
    expr: StatementASTUniquePtr # readwrite, the expression that is returned. Can be None if returns void.

This class of AST represents the return statements, like return 0.

IdentifierExprAST

class IdentifierExprAST(ExprAST):
    @static
    def new(variable_name: str):... #create a new identifier expression. The variable name of the expression is given by the parameter
    name: str # readwrite, the variable name
    impl: StatementASTUniquePtr # readwrite, the resolved expression AST. The values of this field 
    # should be a subclass of ResolvedIdentifierExprAST

This class represents an identifier expression. For example,

a = b

here a and b are two IdentifierExprASTs. If b is resolved as an variable, the impl field will be a LocalVarExprAST. If b is an function name, the impl field will be a ResolvedFuncExprAST.

ResolvedFuncExprAST

class ResolvedFuncExprAST(ResolvedIdentifierExprAST):
    funcdef: FunctionAST # readwrite, the referenced function 

This AST is used in IdentifierExprAST to represent a function.

ThisExprAST

class ThisExprAST(ExprAST):
    @static
    def new():... #create a new this expression

BoolLiteralExprAST

class BoolLiteralExprAST(ExprAST):
    @static
    def new(value: bool):... # create a new boolean literal expression
    value: bool # readwrite, the value of the boolean literal

The AST for boolean literal, e.g. true

IfBlockAST

class IfBlockAST(StatementAST):
    cond: ExprAST # readonly, the expression to be tested in an "if"
    if_true: StatementASTList # readonly, the list of statements for the "true" condition of the "if" statement
    if_falue: StatementASTList # readonly, the list of statements for the "else" block

ForBlockAST

class ForBlockAST(StatementAST):
    is_dim: bool # readwrite, if the for loop's loop variable is defined in the for-statement
    init_value: StatementASTUniquePtr # readwrite, if is_dim, the variable definition (VariableSingleDefAST).
    # Otherwise, the initial value of the for loop varaiable
    loop_var: ExprAST # readwrite, if is_dim==false, the variable definition of the loop variable. Otherwise, None
    till: StatementASTUniquePtr # readwrite, the expression that marks the end of the loop-variable
    inclusive: bool # readwrite, if true, it is a "for ... to ...". Otherwise, it is a "for ... till ..."
    block: StatementASTList # readwrite, the for loop body

There are two kinds of for-loops in Birdee. One have the loop varaible defined in the "for" statement. The other does not have.

for dim i=0 to 3
    ...
end

for j=0 to 3
    ...
end

The difference of these two kinds of for-loop is reflected in the is_dim field of the AST.

WhileBlockAST

class WhileBlockAST(StatementAST):
    cond: StatementASTUniquePtr # readwrite, the contition expression of the while loop
    block: StatementASTList # readonly, the body of the while loop

LoopControlAST

class LoopControlType(Enum):
    BREAK
    CONTINUE

class LoopControlAST(StatementAST):
    @static
    def new(type: LoopControlType):... # create a new "break" or "continue" statement
    type: LoopControlType # readwrite, the kind of the loop control

This AST is either "break" or "continue"

BinaryExprAST

The expressions that applies an operator on two expressions.

class BinaryOp(Enum):
    BIN_MUL              # *
    BIN_DIV              # /
    BIN_MOD              # %
    BIN_ADD              # +
    BIN_MINUS            # -
    BIN_LT               # <
    BIN_GT               # >
    BIN_LE               # <=
    BIN_GE               # >=
    BIN_EQ               # ==
    BIN_NE               # !=
    BIN_CMP_EQ           # ===
    BIN_CMP_NE           # !==  
    BIN_AND              # &
    BIN_XOR              # ^
    BIN_OR               # |
    BIN_LOGIC_AND        # &&
    BIN_LOGIC_OR         # ||
    BIN_ASSIGN           # =

class BinaryExprAST(ExprAST):
    @static
    def new(op: BinaryOp, lhs: StatementASTUniquePtr, rhs: StatementASTUniquePtr): ...
    #create a new binary expression: lhs op rhs
    is_overloaded: bool # readwrite, if this binary expression is an overloaded function call to a function
    lhs: StatementASTUniquePtr # readwrite, the left hand side expression
    rhs: StatementASTUniquePtr # readwrite, the right hand side expression
    op: BinaryOp # readwrite the operation on the expressions

UnaryExprAST

The expressions that applies an operator on one expression.

class UnaryOp(Enum):
    UNA_NOT        # !
    UNA_ADDRESSOF  # addressof
    UNA_POINTEROF  # pointerof
    UNA_TYPEOF     # typeof

class UnaryExprAST(ExprAST):
    is_overloaded: bool # readwrite, if the expression is an overloaded function call
    # Otherise, None
    arg: StatementASTUniquePtr # the expression that the operator applies to
    op: UnaryOp # the operator

FunctionTemplateInstanceExprAST

The function template instance expression. For example in the code:

add[int,long](1,2)

The expression add[int,long] is a function template instance.

class FunctionTemplateInstanceExprAST(ExprAST):
    expr: UniquePtrStatementAST # readwrite, the function template
    instance: FunctionAST # readwrite, the function template instance

IndexExprAST

The index expression or function template instance expression with only one template parameter.

class IndexExprAST(ExprAST):
    expr: UniquePtrStatementAST # readwrite, the indexed expression (before [...])
    index: UniquePtrStatementAST # readwrite, the index (within [...])
    template_inst: UniquePtrStatementAST # readwrite, if is a template, the template instance expression.
    # otherwise, None
    def is_template_instance()->bool: ... # returns if it is a function template instance

CallExprAST

The AST for function calls.

class CallExprAST(ExprAST):
    callee: UniquePtrStatementAST # readwrite, the callee expression (before (...) )
    args: StatementASTList # readonly, arguments (within (...) )

VariableSingleDefAST

The AST which defines a single variable. Corresponds to dim statements.

class VariableSingleDefAST(StatementAST):
    # the types of captures of a variable
    class CaptureType(Enum):
        CAPTURE_NONE   # not captured
        CAPTURE_REF    # capturing reference to the parent capture object
        CAPTURE_VAL    # capturing the values to the parent capture object
    name: str # readwrite, the name of the variable
    value: StatementASTUniquePtr # readwrite, the initial value of the variable. Can be None
    resolved_type: ResolvedType # readwrite, the type of the variable
    capture_import_type: CaptureType # readwrite, how the captured variable is imported from parent function
    capture_import_idx: int # readwrite, the capture index within the parent function
    capture_export_type: CaptureType # readwrite, how the captured variable is exported to child functions
    capture_export_idx: int # readwrite, the capture index within capture object for the child functions

VariableMultiDefAST

The AST that contains multiple variable definitions.

class VariableMultiDefAST(StatementAST):
    lst: VariableSingleDefASTList # readonly, the variable list

LocalVarExprAST

The AST used by IdentifierExprAST to reference variables.

class LocalVarExprAST(ResolvedIdentifierExprAST):
    @static
    def new(v: VariableSingleDefAST):... # creates a new LocalVarExprAST
    vardef: VariableSingleDefAST # readwrite, the variable definition

FunctionToClosureAST

The AST automatically generated by compiler to convert a function to a closure.

class FunctionToClosureAST(ExprAST):
    func: StatementASTUniquePtr # readwrite, the function/functype expression to be converted

TryBlockAST

The AST for "try ... catch ..." block. A try block may contain several catch variables to catch different types of exception. There are also the same number of "catch" blocks in the AST.

class TryBlockAST(StatementAST):
    try_block: StatementASTList # readonly, try block
    catch_variables: VariableSingleDefASTList # readonly, the definitions of the catch variables
    def get_catch_block(idx: int) -> StatementASTList : ... 
    # get a catch block. The index is from 0 to len(catch_variables) - 1

ThrowAST

class ThrowAST(StatementAST):
    expr: StatementASTUniquePtr # readwrite, the throw expression

Class ASTs

class AccessModifier(Enum):
    PUBLIC
    PRIVATE

class FieldDef:
    @static
    def new(index: int, access: AccessModifier, vdef: StatementASTUniquePtr) -> FieldDefUniquePtr: ...
    # creates a new field, with given index, modifier and the variable definition (given by vdef)
    index: int # readwrite, the index of the field within the class
    access: AccessModifier # readwrite, the access modifier
    decl: StatementASTUniquePtr # readwrite, should be VarialeSingleDefAST. The variable definition

class MemberFunctionDef:
    @static
    def new(access: AccessModifier, fdef: StatementASTUniquePtr) -> MemberFunctionDef: ...
    # creates a new field, with modifier and the FunctionAST (given by fdef)
    access: AccessModifier # readwrite, the access modifier
    decl: StatementASTUniquePtr # readwrite, should be FunctionAST. The function definition

class ClassAST(StatementAST):
    name: str # readwrite, the name of the class
    fields: FieldDefList # readonly, the list of fields
    funcs: MemberFunctionDefList # readonly, the list of member functions
    template_instance_args: TemplateArgumentList # readonly, the list of the template arguement if it is a template instance
    template_source_class: ClassAST # readonly, the template source AST if it is a template instance
    template_param: TemplateParameters_ClassAST # readonly, the template parameters if it is a template
    needs_rtti: bool # readwrite, if the class has RTTI enabled
    is_struct: bool # readonly, if it is a struct instead of a class
    parent_class: ClassAST # readonly, the parent class that this class inherits from
    def is_template_instance() -> bool: ... # returns if it is a template instance
    def is_template() -> bool: ... # returns if it is a template
    def get_unique_name()-> str: ... # returns the fully qualified name of the class
    def find_field(name: str) -> (int,FieldDef): ... # find a field by name from this class. 
    # returns a tuple (int, FieldDef). The int is the number of levels of parents where the field is found.
    # the returned FieldDef may not be in the current class

NewExprAST

The AST for new AST, including newing an array or an object.

class NewExprAST(ExprAST):
    args: StatementASTList # readonly, the list of arguments/dimensions to the new expression
    func: FunctionAST # readwrite, the constructor function to be called

MemberExprAST

The AST for referencing members of an object, or functions/variables imported from other modules.

class MemberExprAST(ResolvedIdentifierExprAST):
    class MemberType(Enum):
        ERROR
        PACKAGE           # if it is an package. e.g. in "mod1.mod2.v1", "mod1.mod2" is of type "PACKAGE"
        FIELD             # a field of an object
        FUNCTION          # a member function of an object
        IMPORTED_DIM      # an imported variable of other modules
        VIRTUAL_FUNCTION  # a virtual function of an object, will read the vtable to generate the callee
        IMPORTED_FUNCTION # a function of an imported module

    @static
    def new(obj: StatementASTUniquePtr, name: str): ... # creates a new member expr "obj.name"
    @static
    def new_func_member(obj: StatementASTUniquePtr, member: MemberFunctionDef): ... # creates a new member function expr

    kind: MemberType # the kind of the member
    obj: StatementASTUniquePtr # the object
    # the following fields can only be read when this class actually stores that kind of value
    # you can get the kind of the exact value by "kind" field
    func: MemberFunctionDef
    field: FieldDef
    imported_func: FunctionAST
    import_dim: VariableSingleDefAST
    def to_string_array()->list: ... # convert the member expr chain to a list of python string

Number Cast AST

This is a class of AST classes. Each converts a number type from another. The FROM and TO in the code below are two number types.

class CastNumberExpr_FROM_TO(ExprAST):
    @static
    def new(expr: StatementASTUniquePtr):... # creates a new Number Cast AST
    expr: StatementASTUniquePtr # the expression to be converted